package com.cyf.util;

import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by cage on 2017/2/24.
 */
public class HttpsUtil {

    private static final Logger logger = LoggerFactory.getLogger(HttpsUtil.class);

    /**
     * PoolingHttpClientConnectionManager
     */
    private static final PoolingHttpClientConnectionManager HTTP_CLIENT_CONNECTION_MANAGER;

    /**
     * CloseableHttpClient
     */
    private static final CloseableHttpClient HTTP_CLIENT;

    private static final String DEFAULT_ENCODING = "UTF-8";

    static {
        HTTP_CLIENT_CONNECTION_MANAGER = new PoolingHttpClientConnectionManager(RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", SSLConnectionSocketFactory.getSocketFactory()).build());
        HTTP_CLIENT_CONNECTION_MANAGER.setDefaultMaxPerRoute(100);
        HTTP_CLIENT_CONNECTION_MANAGER.setMaxTotal(200);
        RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(60000).setConnectTimeout(60000).setSocketTimeout(60000).build();
        HTTP_CLIENT = HttpClientBuilder.create().setConnectionManager(HTTP_CLIENT_CONNECTION_MANAGER).setDefaultRequestConfig(requestConfig).build();
    }

    /**
     * 不可实例化
     */
    private HttpsUtil() {
    }

    public static String post(String url, Object json) {
        CloseableHttpClient client = HttpClients.createDefault();
        String responseText = "";
        CloseableHttpResponse response = null;
        try {
            HttpPost method = new HttpPost(url);

            StringEntity stringEntity = new StringEntity(json.toString(),
                    "UTF-8");// 解决中文乱码问题
            stringEntity.setContentEncoding("UTF-8");
            stringEntity.setContentType("application/json");
            method.setEntity(stringEntity);
            response = client.execute(method);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                responseText = EntityUtils.toString(entity, "utf-8");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return responseText;
    }

    /**
     * POST请求
     *
     * @param url               URL
     * @param inputStreamEntity 请求体
     * @return 返回结果
     */
    public static String post(String url, InputStreamEntity inputStreamEntity) {
        return post(url, inputStreamEntity, null, null);
    }

    public static String post(String url, InputStreamEntity inputStreamEntity, CloseableHttpClient httpClient, String encoding) {
        String result = null;
        try {
            HttpPost httpPost = new HttpPost(url);
            if (encoding == null || "".equals(encoding)) {
                encoding = DEFAULT_ENCODING;
            }
            inputStreamEntity.setContentEncoding(encoding);
            httpPost.setEntity(inputStreamEntity);
            httpClient = httpClient == null ? HTTP_CLIENT : httpClient;
            CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
            result = consumeResponse(httpResponse);
        } catch (ParseException | IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    public static String postText(String url, Map<String, String> paramsMap) {
        return postText(url, paramsMap, null, null, null);
    }

    public static String postText(String url, Map<String, String> paramsMap, Map<String, String> headers, CloseableHttpClient httpClient) {
        return postText(url, paramsMap, headers, httpClient, null);
    }

    public static String postText(String url, Map<String, String> paramsMap, Map<String, String> headers, CloseableHttpClient httpClient, String encoding) {

        String result = null;
        try {
            HttpPost httpPost = new HttpPost(url);
//            httpPost.setHeader(":authority", "wap.cx580.com");
//            httpPost.setHeader(":method", "POST");
//            httpPost.setHeader(":path", "/OAuth/Token");
//            httpPost.setHeader(":scheme", "https");
//            httpPost.setHeader("x-requested-with", "XMLHttpRequest");
//            httpPost.setHeader("content-type", "application/x-www-form-urlencoded; charset=UTF-8");
//            httpPost.setHeader("origin", "https://wap.cx580.com");
            if (headers != null) {
                for (String headerName : headers.keySet()) {
                    if (null != headers.get(headerName)) {
                        httpPost.setHeader(headerName, headers.get(headerName));
                    }
                }
            }

            String urlEncoding;
            if (encoding == null || "".equals(encoding)) {
                urlEncoding = DEFAULT_ENCODING;
            } else {
                urlEncoding = encoding;
            }
            if (paramsMap != null) {
                List<NameValuePair> paramList = new ArrayList<>();
                for (Map.Entry<String, String> param : paramsMap.entrySet()) {
                    NameValuePair pair = new BasicNameValuePair(param.getKey(),
                            param.getValue());

                    paramList.add(pair);
                }
                if (encoding == null) {
                    httpPost.setEntity(new UrlEncodedFormEntity(paramList, urlEncoding));
                }
                httpPost.setEntity(new UrlEncodedFormEntity(paramList, urlEncoding));
            }

            httpClient = httpClient == null ? HTTP_CLIENT : httpClient;
            CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
            result = consumeResponse(httpResponse);
        } catch (ParseException | IOException e) {
            e.printStackTrace();
        }
        return result;
    }


    public static String getRedirectURI(String url, Map<String, String> headers, CloseableHttpClient httpClient) throws IOException {

        String result = null;
        CloseableHttpResponse httpResponse = null;
        try {
            HttpGet httpGet = new HttpGet(url);
            setHeader(headers, httpGet);

            HttpClientContext context = HttpClientContext.create();
            httpClient = httpClient == null ? HTTP_CLIENT : httpClient;
            httpResponse = httpClient.execute(httpGet, context);
            // 获取所有的重定向位置
            List<URI> redirectLocations = context.getRedirectLocations();
            if (redirectLocations != null) {
                logger.debug("redirect url ---------begin---------------");
                for (URI uri : redirectLocations) {
                    System.out.println(uri.toASCIIString());
                    result = uri.toASCIIString();
                }
                logger.debug("redirect url ---------end---------------");
            } else {
                logger.debug("Not found!");
            }
        } catch (UnsupportedEncodingException | ClientProtocolException | ParseException e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != httpResponse) {
                    httpResponse.close();
                }
            } catch (IOException ignored) {
            }
        }
        return result;
    }

    private static void setHeader(Map<String, String> headers, HttpGet httpGet) {
        if (null != headers) {
            for (String headerName : headers.keySet()) {
                String headerValue = headers.get(headerName);
                if (null != headerValue) {
                    httpGet.setHeader(headerName, headerValue);
                }
            }
        }
    }

    public static String get(String url, Map<String, String> headers, CloseableHttpClient httpClient) {
        String result = null;
        try {
            HttpGet httpGet = new HttpGet(url);
            setHeader(headers, httpGet);
            HttpClientContext context = HttpClientContext.create();
            httpClient = httpClient == null ? HTTP_CLIENT : httpClient;
            CloseableHttpResponse httpResponse = httpClient.execute(httpGet, context);
            result = consumeResponse(httpResponse);
        } catch (ParseException | IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    public static String get(String url) {
        String result = "";
        try {
            logger.info("get请求url：{}", url);
            HttpGet httpGet = new HttpGet(url);
            HttpClientContext context = HttpClientContext.create();
            CloseableHttpResponse httpResponse = HTTP_CLIENT.execute(httpGet, context);
            result = consumeResponse(httpResponse);
            logger.info("get请求结果：{}", result);
        } catch (ParseException | IOException e) {
            e.printStackTrace();
            logger.error("get请求url("+ url +")异常：{}", e);
        }
        return result;
    }

    /**
     * 处理返回的请求,拿到返回内容
     *
     * @param httpResponse 要处理的返回
     * @return 返回的内容
     */
    private static String consumeResponse(CloseableHttpResponse httpResponse) {
        String result = null;
        try {
            if (null == httpResponse) {
                return null;
            }
            HttpEntity httpEntity = httpResponse.getEntity();
            if (httpEntity != null) {
                result = EntityUtils.toString(httpEntity, "UTF-8");
                EntityUtils.consume(httpEntity);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (httpResponse != null) {
                    httpResponse.close();
                }
            } catch (IOException ignored) {
            }
        }
        return result;
    }

    public static CloseableHttpClient getHttpClientWithCert(String certPath, String password) {
     /*
        System.setProperty("javax.Net.ssl.trustStore", "D:\\pmcloudsvr\\pmCloudSvr\\src\\main\\resources\\jssecacerts");
        System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
        PoolingHttpClientConnectionManager httpClientConnectionManager =
            new PoolingHttpClientConnectionManager(
                RegistryBuilder.<ConnectionSocketFactory>create()
                        .register("http", PlainConnectionSocketFactory.getSocketFactory())
                        .register("https", SSLConnectionSocketFactory.getSocketFactory()).build());*/

        PoolingHttpClientConnectionManager httpClientConnectionManager;
        // 获得密匙库
        KeyStore trustStore;
        try {
            trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            //格式化证书路径
            String downloadPath = certPath;
            FileInputStream instream = new FileInputStream(new File(downloadPath));
            // 密匙库的密码
            trustStore.load(instream, password.toCharArray());
            // 注册密匙库
            org.apache.http.conn.ssl.SSLSocketFactory socketFactory = new org.apache.http.conn.ssl.SSLSocketFactory(trustStore);
            // 不校验域名
            socketFactory
                    .setHostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            httpClientConnectionManager =
                    new PoolingHttpClientConnectionManager(
                            RegistryBuilder.<ConnectionSocketFactory>create()
                                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
                                    .register("https", socketFactory).build());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        httpClientConnectionManager.setDefaultMaxPerRoute(100);
        httpClientConnectionManager.setMaxTotal(200);
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(60000)
                .setConnectTimeout(60000)
                .setSocketTimeout(60000).build();
        return HttpClientBuilder.create()
                .setConnectionManager(httpClientConnectionManager)
                .setDefaultRequestConfig(requestConfig).build();
    }

    public static byte[] downloadImage(String downloadUrl) {
        InputStream inputStream = null;
        HttpURLConnection httpURLConnection = null;
        try {
            URL url = new URL(downloadUrl);
            httpURLConnection = (HttpURLConnection) url.openConnection();
            // 设置连接网络的超时时间
            httpURLConnection.setConnectTimeout(3000);
            httpURLConnection.setDoInput(true);
            // 设置本次http请求使用get方式请求
            httpURLConnection.setRequestMethod("GET");
            int responseCode = httpURLConnection.getResponseCode();
            if (responseCode == 200) {
                // 从服务器获得一个输入流
                inputStream = httpURLConnection.getInputStream();
                int count = 0;
                while (count == 0) {
                    count = inputStream.available();
                }
                byte[] b = new byte[count];
                inputStream.read(b);
                return b;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}
